package com.woniu.cq.mallorder.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniu.cq.mallorder.annotation.CloudLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author Daniel
 * @version 1.0.0
 * @ClassName LockAdvice
 * @Description 封装aop实现注解加锁
 * @createTime 2020年09月29日 21:47:00
 */
@Component
@Aspect
public class LockAdvice {
    @Autowired
    private RedissonClient redissonClient;

    public String getValue(Field field, Object obj) {
        String name = field.getName();
        String getName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
        try {
            Method method = obj.getClass().getDeclaredMethod(getName);
            return method.invoke(obj).toString();
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @description: 环绕通知
     * @param: pj
     * @return: java.lang.Object
     */
    @Around("execution(* * ..service..*.*(..)) && @annotation(com.woniu.cq.mallorder.annotation.CloudLock)")
    public Object lock(ProceedingJoinPoint pj) {
        Object value = null;
        RLock lock = null;
        try {
            //获取方法
            MethodSignature ms = (MethodSignature) pj.getSignature();
            Method method = ms.getMethod();
            //获得注解类
            CloudLock cl = method.getDeclaredAnnotation(CloudLock.class);
            String key = cl.value();
            String end = null;
            Object par = null;
            if (!"".equals(cl.fileName().trim())) {
                if (cl.preIndex() >= 0) {
                    par = pj.getArgs()[cl.preIndex()];
                } else {
                    par = pj.getArgs()[0];
                    Field field = par.getClass().getDeclaredField(cl.fileName());
                    end = getValue(field, par);
                }
            }
            if (end != null){
                key = key + ":" + end;
            }
            lock = redissonClient.getLock(key);
            lock.tryLock(cl.timeout(), cl.lockTimeout(), TimeUnit.SECONDS);
            Thread.sleep(1000);
            value = pj.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
        return value;
    }
}
